import logging
from threading import Thread

import cv2
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtWidgets import QGridLayout, QLabel, QWidget, QPushButton, QDialog, QComboBox, QVBoxLayout, QHBoxLayout, \
    QStackedLayout, QScrollArea

from config import config_file_path
from prepare_for_examen import right_icon, icon_size
from system import run_command
import numpy as np
from PIL import Image

scanned_image_filename = '/tmp/scanned_test_page.jpg'


class ScanSettingsWidget(QDialog):
    def __init__(self, mainwindow=None):
        QDialog.__init__(self)
        self.mainwindow = mainwindow
        self.initUI()

    def refresh_scan_devices(self):
        devices_list = run_command('scanimage -f %d%n').strip().split('\n')
        self.scaners_combobox.clear()
        self.scaners_combobox.addItems(devices_list)
        self.status_bar_label.setText('Список устройств обновлён.')
        self.scan_button.setEnabled(True)
        saved_scaner = run_command(f'py-ini-config get {config_file_path} ScanerSettings scaner').strip()
        try:
            self.scaners_combobox.setCurrentText(saved_scaner)
        except Exception as e:
            logging.info(f'Был сохранён сканер {saved_scaner}, но не удалось установить его по умолчанию. '
                         f'Исключение: {e}')

    def thread_for_refreshing_scan_devices(self):
        thread = Thread(target=self.refresh_scan_devices)
        self.status_bar_label.setText('Обновляется список устройств...')
        self.scan_button.setDisabled(True)
        self.set_right_widget_for_scan_test_page()
        thread.start()

    def scan_test_page(self):
        run_command(f'scanimage -d "{self.scaners_combobox.currentText().strip()}" '
                    f'--format jpeg > {scanned_image_filename}')
        self.scanned_pixmap = QPixmap(scanned_image_filename).scaled(210 * 1.5, 297 * 1.5)
        self.preview_scanned_page.setFixedSize(self.scanned_pixmap.width(), self.scanned_pixmap.height())
        self.preview_scanned_page.setPixmap(self.scanned_pixmap)
        img = np.array(Image.open(scanned_image_filename))
        qr_detector = cv2.QRCodeDetector()
        data, vertices_array, binary_qrcode = qr_detector.detectAndDecode(img)
        if data:
            self.qrcode_recognition_label.setText(data)
        else:
            self.qrcode_recognition_label.setText('Не удалось распознать QR-код на отсканированном изображении')
        bar_detector = cv2.barcode_BarcodeDetector()
        ok, decoded_info, decoded_type, corners = bar_detector.detectAndDecode(img)
        if ok:
            decoded_barcodes = [i for i in decoded_info if i]
            self.barcode_recognition_label.setText(f'Распознано {len(decoded_barcodes)} штрихкодов: '
                                                   f'{", ".join(decoded_barcodes)}')
        else:
            self.barcode_recognition_label.setText('Не удалось распознать штрихкод на отсканированном изображении')

        self.set_right_widget_for_approving_scan_quality()

    def save_scanner_settings(self):
        run_command(f'py-ini-config set '
                    f'{config_file_path} ScanerSettings scaner "{self.scaners_combobox.currentText().strip()}"')
        try:
            self.mainwindow.prepare_for_examen_widget.scaner_label.icon.setPixmap(
                QIcon.fromTheme(right_icon).pixmap(icon_size))
            self.mainwindow.prepare_for_examen_widget.chosen_scaner_label.setText(
                f'Выбранный сканер: {self.scaners_combobox.currentText().strip()}')
        except Exception as e:
            logging.info(f'Не удалось обновить информацию о сканере в виджете настройки экзамена. Исключение: {e}')
        self.accept()

    def set_right_widget_for_scan_test_page(self):
        self.stacked_layout_for_right_widget.setCurrentIndex(0)
        self.save_button.setDisabled(True)

    def set_right_widget_for_approving_scan_quality(self):
        self.stacked_layout_for_right_widget.setCurrentIndex(1)

    def change_pixmap_size(self):
        try:
            width, height = self.scanned_pixmap.width(), self.scanned_pixmap.height()
            if self.sender().objectName() == 'plus_button':
                width, height = width * 1.1, height * 1.1
            else:
                width, height = width * 0.9, height * 0.9
            self.scanned_pixmap = QPixmap(scanned_image_filename).scaled(width, height)
            self.preview_scanned_page.setFixedSize(self.scanned_pixmap.width(), self.scanned_pixmap.height())
            self.preview_scanned_page.setPixmap(self.scanned_pixmap)
        except Exception as e:
            logging.info(f'Не удалось изменить размер изображения. Исключение: {e}')

    def initUI(self):
        layout = QGridLayout()
        self.setLayout(layout)

        layout.addWidget(QLabel('Сканер'), 0, 0)

        # эти элементы интерфейса нужны заранее
        self.status_bar_label = QLabel('Обновляется список устройств...')
        self.scan_button = QPushButton('Отсканировать')
        self.stacked_layout_for_right_widget = QStackedLayout()
        self.save_button = QPushButton('Сохранить')

        self.scaners_combobox = QComboBox()
        self.thread_for_refreshing_scan_devices()
        layout.addWidget(self.scaners_combobox, 1, 0)
        find_scaner_button = QPushButton('Найти сканер')
        find_scaner_button.clicked.connect(self.thread_for_refreshing_scan_devices)
        layout.addWidget(find_scaner_button, 1, 1)
        attention_label = QLabel('<b>ⓘ Внимание!</b> '
                                 'При смене выбранного сканера необходимо выполнить тестовое сканирование повторно.')
        attention_label.setStyleSheet('QLabel {background-color: #d0d0ff; margin: 5px; color: black;}')
        layout.addWidget(attention_label, 2, 0, 1, 2)

        left_widget = QWidget()
        left_widget_layout = QHBoxLayout()
        left_widget.setLayout(left_widget_layout)

        scroll_area_for_image = QScrollArea()

        self.preview_scanned_page = QLabel('Нет изображения')
        # scroll_area_for_image.setFixedSize(210 * 1.5, 297 * 1.5)
        scroll_area_for_image.setWidget(self.preview_scanned_page)
        left_widget_layout.addWidget(scroll_area_for_image)

        middle_widget = QWidget()
        middle_widget_layout = QVBoxLayout()
        middle_widget.setLayout(middle_widget_layout)
        plus_button = QPushButton('+')
        plus_button.setFixedWidth(30)
        plus_button.setObjectName('plus_button')
        plus_button.clicked.connect(self.change_pixmap_size)
        middle_widget_layout.addWidget(plus_button)
        minus_button = QPushButton('-')
        minus_button.setFixedWidth(30)
        minus_button.setObjectName('minus_button')
        minus_button.clicked.connect(self.change_pixmap_size)
        middle_widget_layout.addWidget(minus_button)
        middle_widget_layout.addStretch()
        left_widget_layout.addWidget(middle_widget)

        layout.addWidget(left_widget, 3, 0)

        right_widget1 = QWidget()
        right_widget1_layout = QVBoxLayout()
        right_widget1_layout.addWidget(QLabel('<h3>Проверка сканера</h3>'))
        necessary_to_check_scaner_label = QLabel('Выполните проверку сканера (отсканируйте, при наличии, тестовую '
                                                 'страницу проверки качества печати или напечатайте тестовую '
                                                 'страницу из файла и отсканируйте).')
        necessary_to_check_scaner_label.setWordWrap(True)
        right_widget1_layout.addWidget(necessary_to_check_scaner_label)
        self.scan_button.clicked.connect(self.scan_test_page)
        self.scan_button.setDisabled(True)
        right_widget1_layout.addWidget(self.scan_button)
        right_widget1_layout.addStretch()
        right_widget1.setLayout(right_widget1_layout)
        self.save_button.setDisabled(True)

        right_widget2 = QWidget()
        right_widget2_layout = QVBoxLayout()
        right_widget2.setLayout(right_widget2_layout)
        right_widget2_layout.addWidget(QLabel('<h3>Проверка сканера</h3>'))
        right_widget2_layout.addWidget(QLabel('<b>Распознавание ШК:</b>'))
        self.barcode_recognition_label = QLabel('-')
        self.barcode_recognition_label.setWordWrap(True)
        right_widget2_layout.addWidget(self.barcode_recognition_label)
        right_widget2_layout.addWidget(QLabel('<b>Распознавание QR:</b>'))
        self.qrcode_recognition_label = QLabel('-')
        self.qrcode_recognition_label.setWordWrap(True)
        right_widget2_layout.addWidget(self.qrcode_recognition_label)
        after_scan_label = QLabel('После сканирования должно появиться изображение '
                                  'отсканированной тестовой страницы.<br>'
                                  'Оцените соответствие отсканированного изображения '
                                  'тестовой странице.<br>'
                                  'Тестовая страница печати отсканирована корректно?')
        after_scan_label.setWordWrap(True)
        right_widget2_layout.addWidget(after_scan_label)
        yesnowidget = QWidget()
        yesnowidget_layout = QHBoxLayout()
        yesnowidget_layout.setAlignment(Qt.AlignLeft)
        yesnowidget.setLayout(yesnowidget_layout)
        self.yes_button = QPushButton('Да')
        self.yes_button.clicked.connect(lambda: self.save_button.setEnabled(True))
        self.yes_button.setFixedWidth(100)
        self.no_button = QPushButton('Нет')
        self.no_button.clicked.connect(self.set_right_widget_for_scan_test_page)
        self.no_button.setFixedWidth(100)
        yesnowidget_layout.addWidget(self.no_button)
        yesnowidget_layout.addWidget(self.yes_button)
        yesnowidget_layout.addStretch()
        right_widget2_layout.addWidget(yesnowidget)
        right_widget2_layout.addStretch()

        self.stacked_layout_for_right_widget.addWidget(right_widget1)
        self.stacked_layout_for_right_widget.addWidget(right_widget2)

        self.right_widget = QWidget()
        self.right_widget.setLayout(self.stacked_layout_for_right_widget)
        self.set_right_widget_for_scan_test_page()
        layout.addWidget(self.right_widget, 3, 1)

        cancel_button = QPushButton('Отменить')
        cancel_button.clicked.connect(lambda: self.reject())
        layout.addWidget(cancel_button, 4, 0)

        self.save_button.setDisabled(True)
        self.save_button.clicked.connect(self.save_scanner_settings)
        layout.addWidget(self.save_button, 4, 1)

        layout.addWidget(self.status_bar_label, 5, 0, 1, 2)

        layout.setColumnStretch(0, 1)
        layout.setColumnStretch(1, 1)
        self.setMinimumWidth(500)
        self.setWindowTitle('Настройка сканирования')
